﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Media.Effects;
using System.Windows.Threading;
using System.ComponentModel;
using System.Windows.Markup;
using System.IO;
using System.Xml;

namespace BinaryTimesCore
{
    /// <summary>
    /// Interaction logic for BinaryClock.xaml
    /// </summary>
    public partial class BinaryClock : UserControl
    {
        #region fields

        DispatcherTimer timerTime;
        DispatcherTimer timerLocation;

        int curHour;
        int curMinute;
        int curSecond;

        bool init;

        #endregion

        #region properties

        internal Dictionary<int, ContentControl> Nodes { get; private set; }

        #endregion

        #region dependency properties

        public static readonly DependencyProperty HourTemplateProperty = DependencyProperty.Register("HourTemplate", typeof(DataTemplate), typeof(BinaryClock), new UIPropertyMetadata(null, new PropertyChangedCallback(HourTemplateChanged)));
        public DataTemplate HourTemplate
        {
            get { return (DataTemplate)GetValue(HourTemplateProperty); }
            set { SetValue(HourTemplateProperty, value); }
        }

        private static void HourTemplateChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
        {
            BinaryClock binaryClock = source as BinaryClock;

            if (binaryClock != null && binaryClock.Nodes != null)
            {
                for (int i = (int)BinaryTime.HourTens2; i <= (int)BinaryTime.HourOnes1; i <<= 1)
                {
                    binaryClock.Nodes[i].ContentTemplate = (DataTemplate)e.NewValue;
                }
            }
        }

        public static readonly DependencyProperty MinuteTemplateProperty = DependencyProperty.Register("MinuteTemplate", typeof(DataTemplate), typeof(BinaryClock), new UIPropertyMetadata(null, new PropertyChangedCallback(MinuteTemplateChanged)));
        public DataTemplate MinuteTemplate
        {
            get { return (DataTemplate)GetValue(MinuteTemplateProperty); }
            set { SetValue(MinuteTemplateProperty, value); }
        }

        private static void MinuteTemplateChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
        {
            BinaryClock binaryClock = source as BinaryClock;

            if (binaryClock != null && binaryClock.Nodes != null)
            {
                for (int i = (int)BinaryTime.MinuteTens4; i <= (int)BinaryTime.MinuteOnes1; i <<= 1)
                {
                    binaryClock.Nodes[i].ContentTemplate = (DataTemplate)e.NewValue;
                }
            }
        }

        public static readonly DependencyProperty SecondTemplateProperty = DependencyProperty.Register("SecondTemplate", typeof(DataTemplate), typeof(BinaryClock), new UIPropertyMetadata(null, new PropertyChangedCallback(SecondTemplateChanged)));
        public DataTemplate SecondTemplate
        {
            get { return (DataTemplate)GetValue(SecondTemplateProperty); }
            set { SetValue(SecondTemplateProperty, value); }
        }

        private static void SecondTemplateChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
        {
            BinaryClock binaryClock = source as BinaryClock;

            if (binaryClock != null && binaryClock.Nodes != null)
            {
                for (int i = (int)BinaryTime.SecondTens4; i <= (int)BinaryTime.SecondOnes1; i <<= 1)
                {
                    binaryClock.Nodes[i].ContentTemplate = (DataTemplate)e.NewValue;
                }
            }
        }

        #endregion
       

        public BinaryClock()
        {
            InitializeComponent();

            init = false;

            timerTime = new DispatcherTimer();
            timerTime.Tick += new EventHandler(timerTime_Tick);
            timerTime.Interval = TimeSpan.FromMilliseconds(100);

            timerLocation = new DispatcherTimer();
            timerLocation.Tick += new EventHandler(timerLocation_Tick);
            timerLocation.Interval = TimeSpan.FromSeconds(70);

            InitializeNodes();
        }

        public void Start()
        {
            init = true;

            timerTime.Start();
            timerLocation.Start();
        }

        public void Stop()
        {
            timerLocation.Stop();
            timerTime.Stop();

            DrawCurrentTime(0);
        }


        private void InitializeNodes()
        {
            //ensure that the function is only called once
            if (Nodes != null)
                return;

            Nodes = new Dictionary<int, ContentControl>();

            int counter = 0;
            int col = 0;
            int row = 0;

            //for spacing between hour, minute and second
            int timeGroup = 0;


            for (int i = 1; i <= 0x00800000; i <<= 1)
            {
                ContentControl node = new ContentControl
                {
                    VerticalAlignment = VerticalAlignment.Center,
                    HorizontalAlignment = HorizontalAlignment.Center,
                    Margin = new Thickness(4),
                    Visibility = Visibility.Hidden
                };

                Grid.SetRow(node, row);
                Grid.SetColumn(node, col + timeGroup);
                grid.Children.Add(node);
                Nodes.Add(i, node);

                counter++;

                row++;
                if (row > 3)
                    row = 0;

                if (counter % 4 == 0)
                    col++;

                if (counter % 8 == 0)
                    timeGroup++;
            }

            if (LicenseManager.UsageMode == LicenseUsageMode.Designtime)
                DrawCurrentTime((BinaryTime)0x00FFFFFF);
            else
                DrawCurrentTime(0);
        }

        private void ChangeLocation()
        {
            if (this.ActualWidth > 0 && this.ActualHeight > 0)
            {
                Canvas.SetLeft(grid, RandomNumbers.Next(10, this.ActualWidth - grid.ActualWidth - 10));
                Canvas.SetTop(grid, RandomNumbers.Next(10, this.ActualHeight - grid.ActualHeight - 10));
            }
        }

        private BinaryTime ConvertToBinaryTime(int hours, int minutes, int seconds)
        {
            BinaryTime activeNodes = 0;

            //Hours
            if (hours >= 20)
            {
                activeNodes |= BinaryTime.HourTens2;
                hours %= 20;
            }
            if (hours >= 10)
            {
                activeNodes |= BinaryTime.HourTens1;
                hours %= 10;
            }
            if (hours >= 8)
            {
                activeNodes |= BinaryTime.HourOnes8;
                hours %= 8;
            }
            if (hours >= 4)
            {
                activeNodes |= BinaryTime.HourOnes4;
                hours %= 4;
            }
            if (hours >= 2)
            {
                activeNodes |= BinaryTime.HourOnes2;
                hours %= 2;
            }
            if (hours >= 1)
            {
                activeNodes |= BinaryTime.HourOnes1;
                hours %= 1;
            }


            //Minutes
            if (minutes >= 40)
            {
                activeNodes |= BinaryTime.MinuteTens4;
                minutes %= 40;
            }
            if (minutes >= 20)
            {
                activeNodes |= BinaryTime.MinuteTens2;
                minutes %= 20;
            }
            if (minutes >= 10)
            {
                activeNodes |= BinaryTime.MinuteTens1;
                minutes %= 10;
            }
            if (minutes >= 8)
            {
                activeNodes |= BinaryTime.MinuteOnes8;
                minutes %= 8;
            }
            if (minutes >= 4)
            {
                activeNodes |= BinaryTime.MinuteOnes4;
                minutes %= 4;
            }
            if (minutes >= 2)
            {
                activeNodes |= BinaryTime.MinuteOnes2;
                minutes %= 2;
            }
            if (minutes >= 1)
            {
                activeNodes |= BinaryTime.MinuteOnes1;
                minutes %= 1;
            }


            //Seconds
            if (seconds >= 40)
            {
                activeNodes |= BinaryTime.SecondTens4;
                seconds %= 40;
            }
            if (seconds >= 20)
            {
                activeNodes |= BinaryTime.SecondTens2;
                seconds %= 20;
            }
            if (seconds >= 10)
            {
                activeNodes |= BinaryTime.SecondTens1;
                seconds %= 10;
            }
            if (seconds >= 8)
            {
                activeNodes |= BinaryTime.SecondOnes8;
                seconds %= 8;
            }
            if (seconds >= 4)
            {
                activeNodes |= BinaryTime.SecondOnes4;
                seconds %= 4;
            }
            if (seconds >= 2)
            {
                activeNodes |= BinaryTime.SecondOnes2;
                seconds %= 2;
            }
            if (seconds >= 1)
            {
                activeNodes |= BinaryTime.SecondOnes1;
                seconds %= 1;
            }

            return activeNodes;
        }

        private void DrawCurrentTime(BinaryTime activeNodes)
        {
            for (int i = 0x0001; i <= 0x00800000; i <<= 1)
            {
                if (((int)activeNodes & i) == i)
                    Nodes[i].Visibility = Visibility.Visible;
                else
                    Nodes[i].Visibility = Visibility.Hidden;
            }

            ////hours
            //for (int i = 0x0001; i <= 0x00000080; i <<= 1)
            //{
            //    if (((int)activeNodes & i) == i)
            //        nodes[i].Text = "H";
            //    else
            //        nodes[i].Text = "";
            //}

            ////minutes
            //for (int i = 0x0100; i <= 0x0008000; i <<= 1)
            //{
            //    if (((int)activeNodes & i) == i)
            //        nodes[i].Text = "M";
            //    else
            //        nodes[i].Text = "";
            //}

            ////seconds
            //for (int i = 0x00010000; i <= 0x00800000; i <<= 1)
            //{
            //    if (((int)activeNodes & i) == i)
            //        nodes[i].Text = "S";
            //    else
            //        nodes[i].Text = "";
            //}
        }


        private void timerTime_Tick(object sender, EventArgs e)
        {
            int hour = DateTime.Now.Hour;
            int minute = DateTime.Now.Minute;
            int second = DateTime.Now.Second;

            if (curHour == hour && curMinute == minute && curSecond == second)
                return;

            DrawCurrentTime(ConvertToBinaryTime(hour, minute, second));

            curHour = hour;
            curMinute = minute;
            curSecond = second;

            if (init)
            {
                init = false;
                ChangeLocation();
            }
        }

        private void timerLocation_Tick(object sender, EventArgs e)
        {
            ChangeLocation();
        }
    }
}
